package com.frejoys.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.frejoys.common.config.ValueConfig;
import com.frejoys.common.config.WxMaConfiguration;
import com.frejoys.common.dto.admin.*;
import com.frejoys.common.dto.common.UserIdDto;
import com.frejoys.common.dto.common.login.LoginDto;
import com.frejoys.common.dto.common.login.WxH5LoginDto;
import com.frejoys.common.dto.common.login.WxLoginDto;
import com.frejoys.common.dto.common.user.InfoUpDto;
import com.frejoys.common.enums.*;
import com.frejoys.common.error.HttpStatus;
import com.frejoys.common.exception.GeneralException;
import com.frejoys.common.util.AppConfigUtil;
import com.frejoys.common.util.CacheKeyUtil;
import com.frejoys.common.util.CheckUtil;
import com.frejoys.common.util.CommonUtil;
import com.frejoys.common.util.JwtUtil;
import com.frejoys.common.util.RedisUtil;
import com.frejoys.common.util.RequestUtil;
import com.frejoys.common.util.SnowflakeUtil;
import com.frejoys.common.util.TimeUtil;
import com.frejoys.common.vo.admin.AdminListVo;
import com.frejoys.common.vo.admin.AuthGroupNameVo;
import com.frejoys.common.vo.admin.UserAgentVo;
import com.frejoys.common.vo.admin.UserVo;
import com.frejoys.common.vo.common.LoginVo;
import com.frejoys.common.vo.common.TokenVo;
import com.frejoys.common.vo.common.UserDetailsVo;
import com.frejoys.common.vo.common.WxH5UserInfoVo;
import com.frejoys.common.vo.common.WxH5Vo;
import com.frejoys.dao.entity.*;
import com.frejoys.dao.mapper.*;
import com.frejoys.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

// 用户
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final ValueConfig valueConfig;

    private final RedisUtil redisUtil;

    private final BlackService blackService;

    private final LoginMapper loginMapper;

    private final ResourceLibraryService resourceLibraryService;

    private final OrderMapper orderMapper;

    private final UserWalletMapper userWalletMapper;

    private final UserQrcodeMapper userQrcodeMapper;

    private final CommonService commonService;

    private final VerifyService verifyService;

    private final EventPublisherService eventPublisherService;

    private final UserMapper userMapper;

    private final AgentUserMapper agentUserMapper;

    private final AgentRoleGroupMapper agentRoleGroupMapper;

    private final UserCodeMapper userCodeMapper;

    private final UserLevelMapper userLevelMapper;

    private final StoreEnterMapper storeEnterMapper;

    private final StoreUserMapper storeUserMapper;

    private final GoodsMapper goodsMapper;

    private final AuthGroupAccessMapper authGroupAccessMapper;

    private final AuthGroupMapper authGroupMapper;

    @Override
    @CacheEvict(cacheNames = "user", key = "#userId")
    public void clearUser(Long userId) {

    }

    @Override
    @Cacheable(cacheNames = "user", key = "#userId", unless = "#result == null")
    public User getInfo(Long userId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getId, userId);
        return getOnly(wrapper);
    }

    @Override
    @Cacheable(cacheNames = "user", key = "#dto.userId", unless = "#result == null")
    public User getInfo(UserIdDto dto) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getId, dto.getUserId());
        return getOnly(wrapper);
    }

    @Override
    public User getSimpleInfo(String countryCode, String phone) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getId, User::getNickname, User::getAvatar, User::getPassword, User::getSecret, User::getRole, User::getCreateTime, User::getLastLoginTime, User::getStatus).eq(User::getPhone, phone);

        if (StrUtil.isNotEmpty(countryCode)) {
            // wrapper.eq(User::getCountryCode, countryCode);
        }

        return getOnly(wrapper);
    }

    @Override
    public User getIdStatusByAccount(String countryCode, String phone) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getId, User::getStatus).eq(User::getPhone, phone);

        if (StrUtil.isNotEmpty(countryCode)) {
            wrapper.eq(User::getCountryCode, countryCode);
        }

        return getOnly(wrapper);
    }

    @Override
    public String getAvatarByUserId(Long userId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getAvatar).eq(User::getId, userId);
        User e = getOnly(wrapper);
        return e != null ? e.getAvatar() : "";
    }

    @Override
    @CacheEvict(cacheNames = "user", allEntries = true)
    public boolean upPasswordByUserId(Long userId, String password, String secret) {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(User::getPassword, password).set(User::getSecret, secret);
        wrapper.eq(User::getId, userId);
        return update(wrapper);
    }

    @Override
    @CacheEvict(cacheNames = "user", allEntries = true)
    public boolean logout(Long userId, Integer site, Integer siteType) {
        redisUtil.del(CacheKeyUtil.singleSignCacheKey(userId.toString(), site, siteType));
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    @CacheEvict(cacheNames = "user", allEntries = true)
    public boolean delInfo(Long userId) {
        String avatar = getAvatar(userId);

        // 用户注销
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(User::getStatus, EStatus.off.getValue());
        wrapper.set(User::getNickname, null);
        wrapper.set(User::getAvatar, null);
        wrapper.eq(User::getId, userId);
        update(wrapper);

        // 去除登录信息
        redisUtil.del(CacheKeyUtil.singleSignCacheKey(userId.toString(), ESite.app.getValue(), ESiteType.app_wechat.getValue()));
        redisUtil.del(CacheKeyUtil.singleSignCacheKey(userId.toString(), ESite.app.getValue(), ESiteType.app_h5.getValue()));
        redisUtil.del(CacheKeyUtil.singleSignCacheKey(userId.toString(), ESite.app.getValue(), ESiteType.app_alipay.getValue()));
        redisUtil.del(CacheKeyUtil.singleSignCacheKey(userId.toString(), ESite.store.getValue(), ESiteType.store_wechat.getValue()));
        redisUtil.del(CacheKeyUtil.singleSignCacheKey(userId.toString(), ESite.admin.getValue(), ESiteType.admin_h5.getValue()));

        // 删除头像
        return resourceLibraryService.delInfo(avatar);
    }

    @Override
    public LoginVo getUserLoginInfo(User u, Integer site, Integer siteType) {
        LoginVo vo = new LoginVo();
        BeanUtil.copyProperties(u, vo);
        vo.setUserId(u.getId());
        vo.setAvatar(AppConfigUtil.getUrlPrefix(vo.getAvatar()));

        String uid = u.getId().toString();
        Map<String, Object> map = new HashMap();
        map.put("userId", uid);

        String jwtSecret = valueConfig.getAppJwtSecret();
        Integer jwtExp = valueConfig.getAppJwtExp();

        if (site.equals(ESite.store.getValue())) {
            jwtSecret = valueConfig.getStoreJwtSecret();
            jwtExp = valueConfig.getStoreJwtExp();
        } else if (site.equals(ESite.admin.getValue())) {
            jwtSecret = valueConfig.getAdminJwtSecret();
            jwtExp = valueConfig.getAdminJwtExp();
        }

        vo.setToken(JwtUtil.createToken(map, jwtSecret, jwtExp));

        redisUtil.set(CacheKeyUtil.singleSignCacheKey(uid, site, siteType), SecureUtil.md5(vo.getToken()), jwtExp);

        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginVo login(LoginDto dto, Integer site, Integer siteType) {
        // 电话
        CheckUtil.phone(dto.getPhone());

        // 效验黑名单账户
        blackService.verifyAccount(dto.getCountryCode(), dto.getPhone(), EAccountType.phone.getValue());
        // 效验ip黑名单
        blackService.verifyIp(RequestUtil.ip());

        // 效验验证码
        verifyService.verifyCode(dto.getCountryCode(), dto.getPhone(), 1, dto.getCode());

        User u = getSaveUserInfo(dto.getCountryCode(), dto.getPhone(), ELoginType.phone.getValue(), site, null, null);

        return getUserLoginInfo(u, site, siteType);
    }

    @Override
    public TokenVo refreshToken(Long userId, Integer site, Integer siteType) {
        String uid = userId.toString();
        Map<String, Object> map = new HashMap<>();
        map.put("userId", uid);

        String jwtSecret = valueConfig.getAppJwtSecret();
        Integer jwtExp = valueConfig.getAppJwtExp();

        if (site.equals(ESite.store.getValue())) {
            jwtSecret = valueConfig.getStoreJwtSecret();
            jwtExp = valueConfig.getStoreJwtExp();
        } else if (site.equals(ESite.admin.getValue())) {
            jwtSecret = valueConfig.getAdminJwtSecret();
            jwtExp = valueConfig.getAdminJwtExp();
        }

        String token = JwtUtil.createToken(map, jwtSecret, jwtExp);
        redisUtil.set(CacheKeyUtil.singleSignCacheKey(uid, site, siteType), SecureUtil.md5(token), jwtExp);
        return new TokenVo() {{
            setToken(token);
        }};
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginVo wxLogin(WxLoginDto dto, Integer site, Integer siteType) {

        WxMaService wxService;

        if (site.equals(ESite.app.getValue())) {
            wxService = WxMaConfiguration.getMaService(valueConfig.getAppAppid());
        } else if (site.equals(ESite.store.getValue())) {
            wxService = WxMaConfiguration.getMaService(valueConfig.getStoreAppid());
        } else {
            throw new GeneralException(HttpStatus.wxLoginFail);
        }

        // openid信息
        WxMaJscode2SessionResult session = null;
        // 手机信息
        WxMaPhoneNumberInfo numberInfo = null;

        try {
            session = wxService.getUserService().getSessionInfo(dto.getOpenidCode());
            numberInfo = wxService.getUserService().getNewPhoneNoInfo(dto.getPhoneCode());
        } catch (Exception e) {
            e.printStackTrace();
            throw new GeneralException(HttpStatus.wxLoginError);
        }

        if (session == null || numberInfo == null) {
            throw new GeneralException(HttpStatus.wxLoginError);
        }

        User u = getSaveUserInfo(numberInfo.getCountryCode(), numberInfo.getPhoneNumber(), ELoginType.wechat.getValue(), site, session.getUnionid(), session.getOpenid());

        if (u.getStatus() < EStatus.on.getValue()) {
            throw new GeneralException(HttpStatus.userStatusLoginError);
        }

        return getUserLoginInfo(u, site, siteType);
    }

    /**
     * 微信H5注册登录账户
     *
     * @param dto
     * @param site
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginVo wxH5Login(WxH5LoginDto dto, Integer site, Integer siteType) {

        // 效验黑名单账户
        blackService.verifyAccount(null, dto.getPhone(), EAccountType.phone.getValue());
        // 效验ip黑名单
        blackService.verifyIp(RequestUtil.ip());
        WxH5Vo vo;
        //获取accessToken
        vo = commonService.getWxH5AccessToken(dto.getCode(), site);

        //验证accessToken是否有效
        if (!commonService.validateAccessToken(vo.getAccessToken(), vo.getOpenId())) {
            vo = commonService.H5WxRefreshToken(vo.getRefreshToken(), site);
        }

        //获取用户信息
        WxH5UserInfoVo userInfoVo = commonService.h5GetUserInfo(vo.getAccessToken(), vo.getOpenId());

        if (userInfoVo == null) {
            throw new GeneralException(HttpStatus.wxLoginError);
        }

        User u = getSaveUserInfo(null, dto.getPhone(), ELoginType.wechat.getValue(), site, userInfoVo.getUnionid(), userInfoVo.getOpenid());

        if (u.getStatus() < EStatus.on.getValue()) {
            throw new GeneralException(HttpStatus.userStatusLoginError);
        }

        return getUserLoginInfo(u, site, siteType);
    }

    @Override
    public LoginVo adminLogin(AdminLoginDto dto, Integer site, Integer siteType) {

        // 电话
        CheckUtil.phone(dto.getPhone());
        // 密码
        CheckUtil.password(dto.getPassword());
        // 效验黑名单账户
        blackService.verifyAccount(null, dto.getPhone(), EAccountType.phone.getValue());
        // 效验ip黑名单
        blackService.verifyIp(RequestUtil.ip());

        User u = getSimpleInfo(null, dto.getPhone());

        if (u == null) {
            throw new GeneralException(HttpStatus.userNoExist);
        }

        if (u.getStatus() < EStatus.on.getValue()) {
            throw new GeneralException(HttpStatus.userStatusLoginError);
        }

        if (!CommonUtil.bitExistOffset(u.getRole(), EUserRole.admin.getValue())) {
            throw new GeneralException(HttpStatus.adminRoleFail);
        }

        String key = CacheKeyUtil.loginPasswordErrorCountCacheKey(dto.getPhone(), DateUtil.format(DateUtil.date(), "yyyyMMdd"));

        Object pdCount = redisUtil.get(key);
        if (pdCount != null && Integer.valueOf(pdCount.toString()) > 10) {
            throw new GeneralException(HttpStatus.passwordNumError);
        }

        String password = SecureUtil.hmacMd5(u.getSecret()).digestHex(dto.getPassword());
        if (!u.getPassword().equals(password)) {
            long passwodErrorCount = redisUtil.incr(key);
            if (passwodErrorCount == 1) {
                redisUtil.expire(key, TimeUtil.hourSecond * 5);
            }
            throw new GeneralException(HttpStatus.passwordLoginError);
        }

        redisUtil.del(key);

        return getUserLoginInfo(u, site, siteType);
    }

    @Override
    public boolean changePassword(PasswordChangeDto dto,Long userId) {

        User user = getInfo(userId);
        String oldPassword = SecureUtil.hmacMd5(user.getSecret()).digestHex(dto.getOldPassword());

        //验证旧密码
        if (!oldPassword.equals(user.getPassword())) {
                throw new GeneralException(HttpStatus.passwordError);
            }

        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId,userId)
                        .set(User::getPassword,SecureUtil.hmacMd5(user.getSecret()).digestHex(dto.getNewPassword()));
            baseMapper.update(updateWrapper);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User getSaveUserInfo(String countryCode, String phone, Integer type, Integer site, String unionid, String openid) {
        User u = getSimpleInfo(countryCode, phone);

        // 新增用户
        if (u == null) {

            Integer nt = TimeUtil.unixTime();

            String secret = RandomUtil.randomString(6);

            // 添加用户
            u = new User();
            u.setId(SnowflakeUtil.appNextId());
            u.setNickname("好享免");
            // u.setAvatar("");
            u.setCountryCode(countryCode);
            u.setPhone(phone);
            u.setPassword(SecureUtil.hmacMd5(secret).digestHex("123456"));
            u.setSecret(secret);
            // u.setRole(EUserRole.normal.getValue());
            u.setRole(EUserRole.promotion.getValue());
            // TODO
//            u.setRole(EUserRole.store.getValue());
            u.setCreateTime(nt);
            u.setLastLoginTime(nt);
            u.setStatus(EStatus.on.getValue());
            save(u);

            //添加邀请码
            String code = null;
            for (int i = 0;i < 10; i++) {
                code = getAgentCode();
                if (code != null){
                    break;
                }
            }
            if (code == null){
                throw new GeneralException(HttpStatus.notCodeError);
            }

            UserCode userCode = new UserCode();
            userCode.setCode(code);
            userCode.setUserId(u.getId());
            userCodeMapper.insert(userCode);


//            // 添加登录信息
//            Login l = new Login();
//            l.setOpenid(StrUtil.isNotEmpty(openid) ? openid : phone);
//            l.setUnionid(StrUtil.isNotEmpty(unionid) ? unionid : phone);
//            // l.setNickname("");
//            // l.setAvatar("");
//            l.setType(StrUtil.isNotEmpty(openid) ? ELoginType.wechat.getValue() : ELoginType.phone.getValue());
//            l.setUserId(u.getId());
//            l.setSite(site);
//            l.setCreateTime(u.getCreateTime());
//            loginMapper.insert(l);

            // 添加用户钱包
            UserWallet uw = new UserWallet();
            uw.setUserId(u.getId());
            uw.setSpendMoney(BigDecimal.ZERO);
            uw.setMoney(BigDecimal.ZERO);
            uw.setRebateMoney(BigDecimal.ZERO);
            uw.setRebateMoneyTotal(BigDecimal.ZERO);
            uw.setAgentMoney(BigDecimal.ZERO);
            uw.setAgentMoneyTotal(BigDecimal.ZERO);
            uw.setActiveMoney(BigDecimal.ZERO);
            uw.setActiveMoneyTotal(BigDecimal.ZERO);
            uw.setScore(BigDecimal.ZERO);
            uw.setScoreTotal(BigDecimal.ZERO);
            userWalletMapper.insert(uw);


            // 添加二维码
            UserQrcode uq = new UserQrcode();
            uq.setUserId(u.getId());
            userQrcodeMapper.insert(uq);

        } else {
            if (u.getStatus() < EStatus.off.getValue()) {
                throw new GeneralException(HttpStatus.accountDisable);
            }
        }

        String finalOpenid = StrUtil.isNotEmpty(openid) ? openid : phone;
        String finalUnionid = StrUtil.isNotEmpty(unionid) ? unionid : phone;

        //查询用户登录信息是否存在
        Login login = loginMapper.selectOne(Wrappers.<Login>lambdaQuery().eq(Login::getOpenid, finalOpenid)
                .eq(Login::getType, type).eq(Login::getSite, site).last(" limit 1"));
        if (ObjectUtil.isEmpty(login)) {
            // 添加登录信息
            Login l = new Login();
            l.setOpenid(finalOpenid);
            l.setUnionid(finalUnionid);
            // l.setNickname("");
            // l.setAvatar("");
            l.setType(type);
            l.setUserId(u.getId());
            l.setSite(site);
            l.setCreateTime(u.getCreateTime());
            loginMapper.insert(l);
        }

        // 注销的用户
        if (u.getStatus().equals(EStatus.off.getValue())) {
            upStatus(u.getId(), EStatus.on.getValue());
            u.setStatus(EStatus.on.getValue());
        }

        return u;
    }

    @Override
    @CacheEvict(cacheNames = "user", allEntries = true)
    public boolean upNickname(Long userId, String nickname) {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(User::getNickname, nickname);
        wrapper.eq(User::getId, userId);
        return update(wrapper);
    }

    @Override
    @CacheEvict(cacheNames = "user", allEntries = true)
    public boolean upAvatar(Long userId, String avatar) {
        String ava = getAvatar(userId);

        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(User::getAvatar, avatar);
        wrapper.eq(User::getId, userId);
        update(wrapper);

        // 直接比较删除，如果上传数据为空，会删除数据库已经存在的图片
        resourceLibraryService.delInfo(CommonUtil.getNeedDelImage(ava, avatar));

        return true;
    }

    @Override
    public boolean upRole(Long userId, Integer role) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(User::getRole, role);
        updateWrapper.eq(User::getId, userId);
        return update(updateWrapper);
    }

    @Override
    @CacheEvict(cacheNames = "user", allEntries = true)
    public boolean upInfo(Long userId, InfoUpDto dto) {
        String ava = getAvatar(userId);

        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(User::getNickname, dto.getNickname());

        if (!StrUtil.isEmpty(dto.getAvatar())) {
            wrapper.set(User::getAvatar, dto.getAvatar());
        }

        wrapper.eq(User::getId, userId);
        update(wrapper);

        if (!StrUtil.isEmpty(dto.getAvatar())) {
            // 存在上传头像才比较删除
            resourceLibraryService.delInfo(CommonUtil.getNeedDelImage(ava, dto.getAvatar()));
        }

        return true;
    }

    @Override
    @Cacheable(cacheNames = "user", key = "#root.method.name + '::' + #dto.userId", unless = "#result == null")
    public String getAvatar(Long userId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getAvatar).eq(User::getId, userId);
        User e = getOnly(wrapper);
        return e != null ? e.getAvatar() : null;
    }

    @Override
    @CacheEvict(cacheNames = "user", allEntries = true)
    public boolean upPassword(Long userId, String password) {
        // 更新密码
        String secret = RandomUtil.randomString(6);
        return upPasswordByUserId(userId, SecureUtil.hmacMd5(secret).digestHex(password), secret);
    }

    @Override
    public boolean upStatus(Long userId, Integer status) {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(User::getStatus, status);
        wrapper.eq(User::getId, userId);
        return update(wrapper);
    }


    //获取用户信息
    @Override
    public UserDetailsVo getUserInfo(Long userId, Integer site) {
        //查询用户信息
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
        wrapper.select(User::getNickname, User::getAvatar, User::getRole,User::getPhone);
        wrapper.eq(User::getId, userId);
        wrapper.eq(User::getStatus, EStatus.on.getValue());

        User user = getOnly(wrapper);
        if (user == null) {
            throw new GeneralException(HttpStatus.gainUserError);
        }
        //订单信息
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getUserId, userId);
        Long orderCount = orderMapper.selectCount(queryWrapper);
        UserDetailsVo userDetailsVo = BeanUtil.copyProperties(user, UserDetailsVo.class);
        userDetailsVo.setAvatar(AppConfigUtil.getUrlPrefix(user.getAvatar(), EFileSize.avatar.getValue()));
        userDetailsVo.setUserId(userId);
        userDetailsVo.setOrderCount(orderCount.intValue());

        //查询钱包信息
        LambdaQueryWrapper<UserWallet> walletQueryWrapper = new LambdaQueryWrapper<>();
        walletQueryWrapper.eq(UserWallet::getUserId, userId);
        UserWallet userWallet = userWalletMapper.selectOne(walletQueryWrapper);
        if (userWallet != null) {
            userDetailsVo.setSpendMoney(userWallet.getSpendMoney());
            userDetailsVo.setScore(userWallet.getScore());
            userDetailsVo.setRebateMoney(CommonUtil.bigDecimalAdd(userWallet.getSpendMoney(),userWallet.getRebateMoneyTotal()));
            userDetailsVo.setRebateMoneyTotal(userWallet.getRebateMoneyTotal());
        }
        //查询二维码信息
        UserQrcode uq = userQrcodeMapper.getCodeInfo(userId);
        if (uq != null) {
            if (ESite.app.getValue().equals(site) && StrUtil.isEmpty(uq.getQrCode())) {
                eventPublisherService.sendUserQrCodeService(userId, site);
            }
            userDetailsVo.setQrCode(AppConfigUtil.getUrlPrefix(uq.getQrCode(), EFileSize.qrcode.getValue()));
        }

        //查询邀请码
        String code = userCodeMapper.codeByUserId(userId);
        if (StrUtil.isNotEmpty(code)){
            userDetailsVo.setCode(code);
        }else {
            userDetailsVo.setCode(String.valueOf(userId));
        }

        //查询用户是否已经扫码关联
        LambdaQueryWrapper<UserLevel> userLevelWrapper = new LambdaQueryWrapper<>();
        userLevelWrapper.select(UserLevel::getId).eq(UserLevel::getChildUserId,userId);
        UserLevel userLevel = userLevelMapper.selectOne(userLevelWrapper);

        if (ObjectUtil.isEmpty(userLevel)){
            userDetailsVo.setUserLevelStatus(1);
        }else {
            userDetailsVo.setUserLevelStatus(0);
        }
        return userDetailsVo;
    }


//    @Override
//    public List<User> listUser(Long userId, UserListDto dto,Integer type) {
//
//        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        // 展示下属员工
//        userLambdaQueryWrapper.eq(User::getRole, type);
//        userLambdaQueryWrapper.like(StrUtil.isNotEmpty(dto.getNickname()),User::getNickname, dto.getNickname());
//        userLambdaQueryWrapper.like(StrUtil.isNotEmpty(dto.getPhone()),User::getPhone, dto.getPhone());
//
//        userLambdaQueryWrapper = userQueryWrapper(userLambdaQueryWrapper, userId);
//        if (userLambdaQueryWrapper==null) {
//            return Collections.emptyList();
//        }
//        // 查询子权限组用户
//        Page page = new Page<>(dto.getPage(), dto.getSize());
//        page.setSearchCount(false);
//        return baseMapper.selectPage(page, userLambdaQueryWrapper).getRecords();
//
//    }

    @Override
    public IPage<UserVo> listUser(UserListDto dto) {
        Page page = new Page<>(dto.getPage(), dto.getSize());

        IPage<User> userIPage = baseMapper.listUser(page,dto);
        IPage<UserVo> userVoIPage = userIPage.convert(user -> BeanUtil.copyProperties(user, UserVo.class));

        List<UserVo> userList = userVoIPage.getRecords();

        if (!userList.isEmpty()){
            userList.forEach(userVo -> {
                userVo.setAvatar(AppConfigUtil.getUrlPrefix(userVo.getAvatar()));
            });

        }
        return userVoIPage;

    }
//
//    private LambdaQueryWrapper<User> userQueryWrapper(LambdaQueryWrapper<User> queryWrapper,Long userId){
//        // 获取当前用户拥有的权限组
//        List<AuthGroupAccess> parentUserGroupList = authGroupAccessService.getListByUserId(userId);
//        if (CollectionUtils.isEmpty(parentUserGroupList)) {
//            log.warn("用户无角色组");
//            return null;
//        }
//        LambdaQueryWrapper<AuthGroup> authGroupQueryWrapper = new LambdaQueryWrapper<>();
//        authGroupQueryWrapper.select(AuthGroup::getId,AuthGroup::getPath);
//        authGroupQueryWrapper.in(AuthGroup::getId,
//                parentUserGroupList.stream().map(AuthGroupAccess::getGroupId).collect(Collectors.toList()));
//        List<AuthGroup> parentAuthGroupsList = authGroupService.list(authGroupQueryWrapper);
//        authGroupQueryWrapper.clear();
//        for (AuthGroup authGroup : parentAuthGroupsList) {
//            authGroupQueryWrapper.likeRight(AuthGroup::getPath,authGroup.getPath());
//        }
//        // 获取权限组的子权限组
//        List<AuthGroup> authGroupsList = authGroupService.list(authGroupQueryWrapper);
//
//
//        // 移除本部门，防止查出本部门其他用户的下级
//        List<Integer> subGroupId = authGroupsList.stream().map(AuthGroup::getId).collect(Collectors.toList());
//        subGroupId.removeAll(parentAuthGroupsList.stream().map(AuthGroup::getId).collect(Collectors.toList()));
//
//
//        LambdaQueryWrapper<AuthGroupAccess> authGroupAccessQueryWrapper = new LambdaQueryWrapper<>();
//        authGroupAccessQueryWrapper.select(AuthGroupAccess::getUserId);
//        authGroupAccessQueryWrapper.in(AuthGroupAccess::getGroupId,subGroupId);
//
//        List<AuthGroupAccess> userGroupList = authGroupAccessService.list(authGroupAccessQueryWrapper);
//
//        queryWrapper.in(User::getId,userGroupList.stream().map(AuthGroupAccess::getUserId).collect(Collectors.toList()));
//        return queryWrapper;
//    }

//    @Override
//    public List<User> listBusiness(Long userId, UserListDto dto, Integer type) {
//
//
//        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        userLambdaQueryWrapper.select(User::getId);
//        // 获取平台普通用户
//        userLambdaQueryWrapper.eq(User::getRole, EUserRoleType.normal.getValue());
//        userLambdaQueryWrapper = userQueryWrapper(userLambdaQueryWrapper,userId);
//        if (userLambdaQueryWrapper == null) {
//            return Collections.emptyList();
//        }
//
//        List<Long> userIds = baseMapper.selectList(userLambdaQueryWrapper).stream().map(User::getId).collect(Collectors.toList());
//        // 查询员工推广的商家
//        userLambdaQueryWrapper.clear();
//
//        userLambdaQueryWrapper.eq(User::getRole, EUserRoleType.business.getValue());
//        userLambdaQueryWrapper.like(StrUtil.isNotEmpty(dto.getNickname()),User::getNickname, dto.getNickname());
//        userLambdaQueryWrapper.like(StrUtil.isNotEmpty(dto.getPhone()),User::getPhone, dto.getPhone());
//
//
//        // 查询推广表，获取商家的userId
//        LambdaQueryWrapper<UserPromotion> promotionLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        promotionLambdaQueryWrapper.select(UserPromotion::getChildUserId);
//        promotionLambdaQueryWrapper.in(UserPromotion::getUserId,userIds);
//        List<UserPromotion> promotionList = userPromotionService.list(promotionLambdaQueryWrapper);
//
//        if (CollectionUtils.isEmpty(promotionList)) {
//            return Collections.emptyList();
//        }
//
//        userLambdaQueryWrapper.in(User::getId,promotionList.stream().map(UserPromotion::getChildUserId).collect(Collectors.toList()));
//
//        // 查询子权限组用户
//        Page page = new Page<>(dto.getPage(), dto.getSize());
//        page.setSearchCount(false);
//
//
//        return baseMapper.selectPage(page, userLambdaQueryWrapper).getRecords();
//    }

    @Override
    public IPage<UserVo> listBusiness(UserListDto dto, Integer role) {
        Page page = new Page<>(dto.getPage(), dto.getSize());

        IPage<UserVo> storeUserList = baseMapper.getStoreUserList(page, dto, role);
        List<UserVo> userList = storeUserList.getRecords();

        if (!userList.isEmpty()){
            List<Long> userIds = userList.stream().map(UserVo::getId).toList();

            //查询代理人信息
            LambdaQueryWrapper<StoreEnter> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(StoreEnter::getAgentUserId,StoreEnter::getId,StoreEnter::getUserId)
                            .in(StoreEnter::getUserId,userIds);
            List<StoreEnter> storeEnters = storeEnterMapper.selectList(wrapper);

            Map<Long, StoreEnter> storeEnterMap = new HashMap<>();
            Map<Long, User> userMap = new HashMap<>();

            if (!storeEnters.isEmpty()){
                storeEnterMap = storeEnters.stream().collect(Collectors.toMap(StoreEnter::getUserId, storeEnter -> storeEnter));
                List<Long> agentUserIds = storeEnters.stream().map(StoreEnter::getAgentUserId).distinct().toList();
                if (!agentUserIds.isEmpty()){
                    List<User> users = userMapper.getUserByIds(agentUserIds);
                    userMap = users.stream().collect(Collectors.toMap(User::getId, user -> user));
                }
            }

            //查询店铺数量
            LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(StoreUser::getUserId,StoreUser::getStoreId)
                    .in(StoreUser::getUserId,userIds);
            List<StoreUser> storeUsers = storeUserMapper.selectList(queryWrapper);
            Map<Long, List<StoreUser>> storeUserMap = storeUsers.stream().collect(Collectors.groupingBy(StoreUser::getUserId));

//            //查询商品数量
//            LambdaQueryWrapper<Goods> goodsWrapper = new LambdaQueryWrapper<>();
//            goodsWrapper.select(Goods::getId,Goods::getStoreId)
//                    .in(Goods::getStoreId,storeIds);
//            List<Goods> goodsList = goodsMapper.selectList(goodsWrapper);
//            Map<Integer, List<Goods>> goodsMap = goodsList.stream().collect(Collectors.groupingBy(Goods::getStoreId));

            for (UserVo vo:userList) {

                StoreEnter storeEnter = storeEnterMap.get(vo.getId());
                if (!ObjectUtil.isEmpty(storeEnter)){
                    vo.setStoreEnterId(storeEnter.getId());
                    vo.setAgentUserId(storeEnter.getAgentUserId());
                }

                User user = userMap.get(vo.getAgentUserId());
                if (!ObjectUtil.isEmpty(user)){
                    vo.setAgentNickname(user.getNickname());
                    vo.setAgentPhone(user.getPhone());
                }

                if (storeUserMap.containsKey(vo.getId())){
                    List<StoreUser> list = storeUserMap.get(vo.getId());
                    vo.setStoreCount(list.size());
//                    Integer goodsCount = 0;
//                    for(StoreUser storeUser:list){
//                        List<Goods> goods = goodsMap.get(storeUser.getStoreId());
//                        if (!goods.isEmpty()){
//                            goodsCount += goods.size();
//                        }
//                    }
//                    vo.setGoodsCount(goodsCount);
                }
                vo.setAvatar(AppConfigUtil.getUrlPrefix(vo.getAvatar()));
            }
        }
        return storeUserList;
    }

    @Override
    @CacheEvict(cacheNames = "user", allEntries = true)
    public void changeRole(RoleChangeDto dto) {
        // todo: 判断管理员权限
        // 重置角色
        int initRole = 0;
        List<Integer> roles = dto.getRole();
        // 赋予新角色
        for (Integer role:roles) {
            if (role == EUserRoleType.normal.getValue()){
                initRole = CommonUtil.bitSetOffset(initRole, EUserRole.normal.getValue());
            }
            if (role == EUserRoleType.daren.getValue()){
                initRole = CommonUtil.bitSetOffset(initRole, EUserRole.promotion.getValue());
            }
            if (role == EUserRoleType.agent.getValue()){
                initRole = CommonUtil.bitSetOffset(initRole, EUserRole.agent.getValue());
            }
//            if (role == EUserRoleType.store.getValue()){
//                initRole = CommonUtil.bitSetOffset(initRole, EUserRole.store.getValue());
//            }
            if (role == EUserRoleType.admin.getValue()){
                initRole = CommonUtil.bitSetOffset(initRole, EUserRole.admin.getValue());
            }
        }
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getId,dto.getUserId())
                .set(User::getRole,initRole);
        baseMapper.update(wrapper);
    }

    /**
     * 只查询用户状态和角色
     *
     * @param userId
     */
    @Override
    public User getSimpleUser(Long userId) {
        return baseMapper.getSimpleUser(userId);
    }

    /**
     * 只查询用户状态和角色 多个用户
     *
     * @param userIds
     */
    @Override
    public List<User> getSimpleListUser(List<Long> userIds) {
        return baseMapper.getSimpleListUser(userIds);
    }

    /**
     * 后台设置用户管理
     *
     * @param dto
     */
    @Override
    public boolean setUserRole(UserRoleDto dto) {
        User user = getSimpleUser(dto.getUserId());

        if (user.getStatus() < EStatus.on.getValue()) {
            throw new GeneralException(HttpStatus.userNoExist);
        }

        int newRole;
        if (dto.getIsSet()) {
            // 赋予管理
            newRole = CommonUtil.bitSetOffset(user.getRole(), EUserRole.admin.getValue());
            user.setRole(newRole);

        } else {
            // 取消管理
            newRole = CommonUtil.bitDelOffset(user.getRole(), EUserRole.admin.getValue());
            user.setRole(newRole);
        }
        user.setRole(newRole);
        return updateById(user);
    }


    //校验代理人编号是否错误
    @Override
    public long verifyAgentUserId(Long agentUserId) {
        Long id = userMapper.getCount(agentUserId, EUserRole.agent.getValue(), EStatus.on.getValue());
        if (id == null) {
            throw new GeneralException(HttpStatus.agentError);
        }
        return id;
    }


    //查询代理人列表
    @Override
    public IPage<UserAgentVo> agentListInfo(UserNameAndPhoneDto dto) {
        Page page = new Page<>(dto.getPage(), dto.getSize());

        Page<UserAgentVo> userAgentVoPage = baseMapper.agentListInfo(page,EUserRole.agent.getValue(),EStatus.on.getValue(),dto.getNickname(),dto.getPhone());
        List<UserAgentVo> list = userAgentVoPage.getRecords();
        list.forEach(vo -> {
            vo.setAvatar(AppConfigUtil.getUrlPrefix(vo.getAvatar()));
        });
        return userAgentVoPage;
    }


    @Override
    public IPage<UserAgentVo> notGroupingAgentList(UserNameAndPhoneDto dto) {
        Page page = new Page<>(dto.getPage(), dto.getSize());

        //查询代理人
        Page<UserAgentVo> userAgentVoPage = baseMapper.agentListInfo(page,EUserRole.agent.getValue(),EStatus.on.getValue(),dto.getNickname(),dto.getPhone());
        List<UserAgentVo> list = userAgentVoPage.getRecords();

        if (!list.isEmpty()){
            List<Long> userIds = list.stream().map(UserAgentVo::getId).toList();

            //查询组成员
            LambdaQueryWrapper<AgentUser> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(AgentUser::getUserId,AgentUser::getAgentRoleGroupId,AgentUser::getId)
                    .in(AgentUser::getUserId,userIds);
            List<AgentUser> agentUsers = agentUserMapper.selectList(wrapper);

            Map<Long, AgentUser> agentUserMap = new HashMap<>();
            Map<Integer, String> agentRoleGroupNameMap = new HashMap<>();

            if (!agentUsers.isEmpty()){
                agentUserMap = agentUsers.stream().collect(Collectors.toMap(AgentUser::getUserId,agentUser -> agentUser));
                List<Integer> agentRoleGroupIds = agentUsers.stream().map(AgentUser::getAgentRoleGroupId).distinct().toList();

                //查询组名称
                LambdaQueryWrapper<AgentRoleGroup> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.select(AgentRoleGroup::getName,AgentRoleGroup::getId)
                        .in(AgentRoleGroup::getId,agentRoleGroupIds);
                List<AgentRoleGroup> agentRoleGroups = agentRoleGroupMapper.selectList(queryWrapper);
                agentRoleGroupNameMap = agentRoleGroups.stream().collect(Collectors.toMap(AgentRoleGroup::getId, AgentRoleGroup::getName));

            }

            for (UserAgentVo vo:list) {
                vo.setAvatar(AppConfigUtil.getUrlPrefix(vo.getAvatar()));
                if (agentUserMap.containsKey(vo.getId())){
                    vo.setAgentRoleGroupId(agentUserMap.get(vo.getId()).getAgentRoleGroupId());
                    vo.setAgentUserId(agentUserMap.get(vo.getId()).getId());
                    if (agentRoleGroupNameMap.containsKey(agentUserMap.get(vo.getId()).getAgentRoleGroupId())){
                        vo.setAgentRoleGroupName(agentRoleGroupNameMap.get(agentUserMap.get(vo.getId()).getAgentRoleGroupId()));
                    }
                }
            }
        }
        return userAgentVoPage;
    }


    @Override
    public IPage<UserAgentsVo> notCustodianList(NotCustodianDto dto) {
        Page page = new Page<>(dto.getPage(), dto.getSize());

        //查询代理用户
        Page<UserAgentVo> userAgentVoPage = baseMapper.agentListInfo(page,EUserRole.agent.getValue(),EStatus.on.getValue(),dto.getNickname(),dto.getPhone());
        IPage<UserAgentsVo> voIPage = userAgentVoPage.convert(userAgentVo -> BeanUtil.copyProperties(userAgentVo, UserAgentsVo.class));
        List<UserAgentsVo> list = voIPage.getRecords();

        if (!list.isEmpty()){
            List<Long> userIds = list.stream().map(UserAgentsVo::getId).toList();

            LambdaQueryWrapper<AgentRoleGroup> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(AgentRoleGroup::getPid,AgentRoleGroup::getPath)
                    .eq(AgentRoleGroup::getId,dto.getId());
            AgentRoleGroup agentRoleGroup = agentRoleGroupMapper.selectOne(wrapper);

            Integer id = 0;
            if (agentRoleGroup.getPid() == 0){
                id = dto.getId();
            }else {
                List<String> path = Arrays.asList(agentRoleGroup.getPath().split(","));
                id = Integer.valueOf(path.get(1));
            }

            LambdaQueryWrapper<AgentRoleGroup> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(AgentRoleGroup::getUserId,AgentRoleGroup::getName,AgentRoleGroup::getId)
                    .isNotNull(AgentRoleGroup::getUserId)
                    .apply("FIND_IN_SET('" + id + "', path)")
                    .in(AgentRoleGroup::getUserId,userIds)
                    .or().eq(AgentRoleGroup::getId,id)
                    .in(AgentRoleGroup::getUserId,userIds);
            List<AgentRoleGroup> agentRoleGroups = agentRoleGroupMapper.selectList(queryWrapper);
            Map<Long, List<AgentRoleGroup>> agentRoleGroupMap = agentRoleGroups.stream().collect(Collectors.groupingBy(AgentRoleGroup::getUserId));

            for (UserAgentsVo vo:list) {
                vo.setAvatar(AppConfigUtil.getUrlPrefix(vo.getAvatar()));

                List<GroupNameVo> voList = new ArrayList<>();
                if (agentRoleGroupMap.containsKey(vo.getId())){
                    List<AgentRoleGroup> group = agentRoleGroupMap.get(vo.getId());
                    for (AgentRoleGroup g:group) {
                        GroupNameVo groupNameVo = new GroupNameVo();
                        groupNameVo.setAgentRoleGroupId(g.getId());
                        groupNameVo.setAgentRoleGroupName(g.getName());
                        voList.add(groupNameVo);
                    }
                }
                vo.setGroupNameVos(voList);
            }
        }
        return voIPage;
    }

    @Override
    public Long getUserIdByPhone(String phone) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getId).eq(User::getPhone, phone);
        User m = getOnly(wrapper);
        return m != null ? m.getId() : null;
    }

    @Override
    public Long phoneByUserId(String phone) {
        Long userId = userMapper.phoneByUserId(phone);
        if (userId == null){
            throw new GeneralException(HttpStatus.notUserError);
        }
        return userId;
    }


    /**生成代理人邀请码
     *
     * @param codes 数据库的邀请码
     * @return
     */
    @Override
    public String getAgentCode(){

        List<String> codeList = new ArrayList<>();
        for (int i = 0;i < 100; i++) {
            codeList.add(RandomUtil.randomString(6));
        }

        LambdaQueryWrapper<UserCode> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(UserCode::getCode).in(UserCode::getCode,codeList);
        List<UserCode> userCodes = userCodeMapper.selectList(wrapper);
        List<String> codes = userCodes.stream().map(UserCode::getCode).toList();

        List<String> list = CollUtil.subtract(codeList, codes).stream().toList();

        if (list.isEmpty()){
            return null;
        }
        return list.get(0);
    }


    @Override
    public IPage<AdminListVo> adminList(UserNameAndPhoneDto dto) {
        Page page = new Page<>(dto.getPage(), dto.getSize());

        IPage<AdminListVo> userPage = userMapper.adminList(page,dto,EUserRole.admin.getValue());
        List<AdminListVo> list = userPage.getRecords();

        if (!list.isEmpty()){

            List<Long> userIds = list.stream().map(AdminListVo::getId).toList();

            //查询用户权限
            LambdaQueryWrapper<AuthGroupAccess> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(AuthGroupAccess::getUserId,userIds);
            List<AuthGroupAccess> authGroupAccesses = authGroupAccessMapper.selectList(wrapper);

            Map<Long, List<AuthGroupAccess>> listMap = authGroupAccesses.stream().collect(Collectors.groupingBy(AuthGroupAccess::getUserId));
            List<Integer> groupIds = authGroupAccesses.stream().map(AuthGroupAccess::getGroupId).distinct().toList();

            Map<Integer, String> groupNameMap = new HashMap<>();
            if (!groupIds.isEmpty()){

                //查询权限名
                LambdaQueryWrapper<AuthGroup> groupWrapper = new LambdaQueryWrapper<>();
                groupWrapper.select(AuthGroup::getId,AuthGroup::getName)
                        .in(AuthGroup::getId,groupIds)
                        .eq(AuthGroup::getStatus,EStatus.on.getValue());
                List<AuthGroup> authGroups = authGroupMapper.selectList(groupWrapper);
                groupNameMap = authGroups.stream().collect(Collectors.toMap(AuthGroup::getId, AuthGroup::getName));
            }

            for (AdminListVo vo:list) {

                List<AuthGroupNameVo> vos = new ArrayList<>();

                //插入管理员权限名
                if (listMap.containsKey(vo.getId())){

                    List<AuthGroupAccess> accessList = listMap.get(vo.getId());
                    List<Integer> groupIdList = accessList.stream().map(AuthGroupAccess::getGroupId).toList();

                    if (!groupIdList.isEmpty()){

                        for (Integer id:groupIdList) {

                            AuthGroupNameVo authGroupNameVo = new AuthGroupNameVo();

                            if (groupNameMap.containsKey(id)){
                                authGroupNameVo.setId(id);
                                authGroupNameVo.setName(groupNameMap.get(id));
                                vos.add(authGroupNameVo);
                            }
                        }
                    }
                }
                vo.setAuthGroupNameVos(vos);
                vo.setAvatar(AppConfigUtil.getUrlPrefix(vo.getAvatar()));
            }
        }
        return userPage;
    }

    @Override
    public List<UserAgentVo> agentList(UserNameAndPhoneDto dto) {
        Page page = new Page<>(dto.getPage(), dto.getSize());
        page.setSearchCount(false);

        Page<UserAgentVo> userAgentVoPage = baseMapper.agentListInfo(page,EUserRole.agent.getValue(),EStatus.on.getValue(),dto.getNickname(),dto.getPhone());
        List<UserAgentVo> list = userAgentVoPage.getRecords();
        list.forEach(vo -> {
            vo.setAvatar(AppConfigUtil.getUrlPrefix(vo.getAvatar()));
        });
        return list;
    }
}